char *deploy_path = NULL;
char srcpath[PATH_MAX];
char destpath[PATH_MAX];
- char newroot[PATH_MAX];
struct stat stbuf;
int orig_cwd_dfd;
deploy_path = resolve_deploy_path (root_mountpoint);
- /* Create a temporary target for our mounts in the initramfs; this will
- * be moved to the new system root below.
- */
- snprintf (newroot, sizeof(newroot), "%s.tmp", root_mountpoint);
- if (mkdir (newroot, 0755) < 0)
- {
- perrorv ("Couldn't create temporary sysroot '%s': ", newroot);
- exit (EXIT_FAILURE);
- }
-
/* Work-around for a kernel bug: for some reason the kernel
* refuses switching root if any file systems are mounted
* MS_SHARED. Hence remount them MS_PRIVATE here as a
}
/* Make deploy_path a bind mount, so we can move it later */
- if (mount (deploy_path, newroot, NULL, MS_BIND, NULL) < 0)
+ if (mount (deploy_path, deploy_path, NULL, MS_BIND, NULL) < 0)
{
perrorv ("failed to initial bind mount %s", deploy_path);
exit (EXIT_FAILURE);
/* Link to the deployment's /var */
snprintf (srcpath, sizeof(srcpath), "%s/../../var", deploy_path);
- snprintf (destpath, sizeof(destpath), "%s/var", newroot);
+ snprintf (destpath, sizeof(destpath), "%s/var", deploy_path);
if (mount (srcpath, destpath, NULL, MS_MGC_VAL|MS_BIND, NULL) < 0)
{
perrorv ("failed to bind mount %s to %s", srcpath, destpath);
snprintf (srcpath, sizeof(srcpath), "%s/boot/loader", root_mountpoint);
if (lstat (srcpath, &stbuf) == 0 && S_ISLNK (stbuf.st_mode))
{
- snprintf (destpath, sizeof(destpath), "%s/boot", newroot);
+ snprintf (destpath, sizeof(destpath), "%s/boot", deploy_path);
if (lstat (destpath, &stbuf) == 0 && S_ISDIR (stbuf.st_mode))
{
snprintf (srcpath, sizeof(srcpath), "%s/boot", root_mountpoint);
}
}
- /* Here we do a dance to chdir to the newroot so that we can have
+ /* Here we do a dance to chdir to the deploy_path so that we can have
* the potential overlayfs mount points not look ugly. However...I
* think we could do this a lot earlier and make all of the mounts
* here just be relative.
exit (EXIT_FAILURE);
}
- if (chdir (newroot) < 0)
+ if (chdir (deploy_path) < 0)
{
- perrorv ("failed to chdir to newroot");
+ perrorv ("failed to chdir to deploy_path");
exit (EXIT_FAILURE);
}
touch_run_ostree ();
- /* Move physical root to $deployment/sysroot */
- snprintf (destpath, sizeof(destpath), "%s/sysroot", newroot);
- if (mount (root_mountpoint, destpath, NULL, MS_MOVE, NULL) < 0)
+ /* In this instance typically we have our ready made-up up root at
+ * /sysroot/ostree/deploy/.../ (deploy_path) and the real rootfs at
+ * /sysroot (root_mountpoint). We want to end up with our made-up root at
+ * /sysroot/ and the real rootfs under /sysroot/sysroot as systemd will be
+ * responsible for moving /sysroot to /.
+ *
+ * We need to do this in 3 moves to avoid trying to move /sysroot under
+ * itself:
+ *
+ * 1. /sysroot/ostree/deploy/... -> /sysroot.tmp
+ * 2. /sysroot -> /sysroot.tmp/sysroot
+ * 3. /sysroot.tmp -> /sysroot
+ */
+ if (mkdir ("/sysroot.tmp", 0755) < 0)
{
- perrorv ("Failed to MS_MOVE %s to '%s'", root_mountpoint, destpath);
+ perrorv ("couldn't create temporary sysroot /sysroot.tmp: ");
exit (EXIT_FAILURE);
}
- /* Now that we've set up all the bind mounts in /sysroot.tmp which
- * points to the deployment, move it /sysroot. From there,
- * systemd's initrd-switch-root.target will take over.
- */
- if (mount (newroot, root_mountpoint, NULL, MS_MOVE, NULL) < 0)
+ if (mount (deploy_path, "/sysroot.tmp", NULL, MS_MOVE, NULL) < 0)
+ {
+ perrorv ("failed to MS_MOVE '%s' to '/sysroot.tmp'", deploy_path);
+ exit (EXIT_FAILURE);
+ }
+
+ if (mount (root_mountpoint, "/sysroot.tmp/sysroot", NULL, MS_MOVE, NULL) < 0)
+ {
+ perrorv ("failed to MS_MOVE '%s' to '/sysroot.tmp/sysroot'",
+ root_mountpoint);
+ exit (EXIT_FAILURE);
+ }
+
+ if (mount ("/sysroot.tmp", root_mountpoint, NULL, MS_MOVE, NULL) < 0)
{
perrorv ("failed to MS_MOVE %s to %s", deploy_path, root_mountpoint);
exit (EXIT_FAILURE);